home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK1.toast / Development Kits (Disc 1) / Apple Game Sprockets / Examples / DroneZone / DZGame.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-16  |  17.2 KB  |  750 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    File:        DZGame.c
  3.  *    Author:        Dan Venolia
  4.  *
  5.  *    Contents:    Handles the game play.
  6.  *
  7.  *    Copyright © 1996 Apple Computer, Inc.
  8.  */
  9.  
  10. #include <assert.h>
  11. #include <string.h>
  12.  
  13. #include <Events.h>
  14. #include <Fonts.h>
  15. #include <QDOffscreen.h>
  16. #include <Timer.h>
  17. #include <Types.h>
  18.  
  19. #include <QD3D.h>
  20. #include <QD3DGeometry.h>
  21. #include <QD3DMath.h>
  22. #include <QD3DSet.h>
  23.  
  24. #include "SoundSprocket.h"
  25.  
  26. #include "DZDisplay.h"
  27. #include "DZDrone.h"
  28. #include "DZGame.h"
  29. #include "DZInput.h"
  30. #include "DZKeyCap.h"
  31. #include "DZSound.h"
  32. #include "DZSpace.h"
  33.  
  34. #ifndef ONE_DRONE
  35.     #define ONE_DRONE        0
  36. #endif
  37.  
  38.  
  39.  
  40. #define DEFAULT_INTERVAL    0.05        // Initial frame rate -- just a guess
  41. #define MAX_INTERVAL        0.25        // Limit on seconds per frame
  42.  
  43. #define KEY_ROTATE_RATE        1.0            // Radians per second while key is down
  44. #define INV_SQRT_TWO        0.707
  45.  
  46. #define AXIS_ROTATE_RATE    3.0            // Radians per second for full joystick throw
  47.  
  48.  
  49. enum {
  50.     #if ONE_DRONE
  51.         kGameAutoDroneCount = 1            // Number of autopilot drones
  52.     #else
  53.         kGameAutoDroneCount = 4            // Number of autopilot drones
  54.     #endif
  55. };
  56.  
  57.  
  58. float                        gGameInterval            = DEFAULT_INTERVAL;
  59. float                        gGameFramesPerSecond    = 1.0/DEFAULT_INTERVAL;
  60.  
  61. static TGameState            gGameState                = kGameState_Stopped;
  62.  
  63. static unsigned long        gGameTime                = 0;        // Last frame time
  64. static KeyMap                gGameKeyMap;
  65.  
  66. static short                gGameDirectionalKeyCap    = 0;        // Last directional keycap pressed
  67. static Boolean                gGameDirectionalKeyDown    = false;    // Pressed recently?
  68.  
  69. static Boolean                gGameHUDVisible            = true;
  70.  
  71. static TDroneObject            gGameSelfDrone            = NULL;
  72.  
  73. static GWorldPtr            gGameFPSGWorld            = NULL;
  74. static TQ3GeometryObject    gGameFPSMarker            = NULL;
  75. static TQ3MarkerData        gGameFPSMarkerData;
  76. static Boolean                gGameFPSVisible            = false;
  77.  
  78. static TQ3GeometryObject    gGameCrossHairs            = NULL;
  79. static unsigned long        gGameCrossHairsData[32]    = {
  80.     0x00000000, 0x00000000, 0x00000000, 0x00000000,
  81.     0x00000000, 0x00010000, 0x00000000, 0x00010000,
  82.     0x00000000, 0x00054000, 0x00101000, 0x00228800,
  83.     0x00082000, 0x00400400, 0x00101000, 0x05400540,
  84.     0x00101000, 0x00400400, 0x00082000, 0x00228800,
  85.     0x00101000, 0x00054000, 0x00000000, 0x00010000,
  86.     0x00000000, 0x00010000, 0x00000000, 0x00000000,
  87.     0x00000000, 0x00000000, 0x00000000, 0x00000000
  88. };
  89.  
  90.  
  91. static void Game_DirectionalKey(
  92.     void);
  93.  
  94. static void Game_CursorKey(
  95.     void);
  96.  
  97.  
  98. /* =============================================================================
  99.  *        Game_Init (external)
  100.  *
  101.  *    Initializes the game stuff.
  102.  * ========================================================================== */
  103. void Game_Init(
  104.     void)
  105. {
  106.     Rect                bounds;
  107.     PixMapHandle        pixMapHandle;
  108.     CGrafPtr            savePort;
  109.     GDHandle            saveGDevice;
  110.     TQ3MarkerData        markerData;
  111.     TQ3ColorRGB            color;
  112.     
  113.     // Set up the 3D sound listener
  114.     Sound_GetListener();
  115.     
  116.     // Create the FPS marker
  117.     bounds.top    = 0;
  118.     bounds.left   = 0;
  119.     bounds.bottom = 12;
  120.     bounds.right  = 31;
  121.     
  122.     gGameFPSGWorld = NULL;
  123.     NewGWorld(&gGameFPSGWorld, 1, &bounds, NULL, NULL, 0);
  124.     assert(gGameFPSGWorld != NULL);
  125.     
  126.     LockPixels(gGameFPSGWorld->portPixMap);
  127.     
  128.     GetGWorld(&savePort, &saveGDevice);
  129.     SetGWorld(gGameFPSGWorld, NULL);
  130.     
  131.     TextFont(geneva);
  132.     TextSize(10);
  133.     
  134.     EraseRect(&gGameFPSGWorld->portRect);
  135.     
  136.     SetGWorld(savePort, saveGDevice);
  137.     
  138.     pixMapHandle = GetGWorldPixMap(gGameFPSGWorld);
  139.     
  140.     gGameFPSMarkerData.location.x            = 0.0;
  141.     gGameFPSMarkerData.location.y            = 0.0;
  142.     gGameFPSMarkerData.location.z            = 0.0;
  143.     gGameFPSMarkerData.xOffset                = -(bounds.left+bounds.right+1 >> 1);
  144.     gGameFPSMarkerData.yOffset                = -(bounds.top+bounds.bottom+1 >> 1);
  145.     gGameFPSMarkerData.bitmap.image            = (unsigned char*) GetPixBaseAddr(pixMapHandle);
  146.     gGameFPSMarkerData.bitmap.width            = bounds.right-bounds.left;
  147.     gGameFPSMarkerData.bitmap.height        = bounds.bottom-bounds.top;
  148.     gGameFPSMarkerData.bitmap.rowBytes        = (*pixMapHandle)->rowBytes & 0x00003FFF;
  149.     gGameFPSMarkerData.bitmap.bitOrder        = kQ3EndianBig;
  150.     gGameFPSMarkerData.markerAttributeSet    = Q3AttributeSet_New();
  151.     assert(gGameFPSMarkerData.markerAttributeSet != NULL);
  152.     
  153.     color.r = 1.0;
  154.     color.g = 1.0;
  155.     color.b = 0.4;
  156.     
  157.     Q3AttributeSet_Add(gGameFPSMarkerData.markerAttributeSet, kQ3AttributeTypeDiffuseColor, &color);
  158.     
  159.     gGameFPSMarker = Q3Marker_New(&gGameFPSMarkerData);
  160.     
  161.     // Create the crosshairs
  162.     markerData.location.x            = 0.0;
  163.     markerData.location.y            = 0.0;
  164.     markerData.location.z            = 0.0;
  165.     markerData.xOffset                = -15;
  166.     markerData.yOffset                = -15;
  167.     markerData.bitmap.image            = (unsigned char*) gGameCrossHairsData;
  168.     markerData.bitmap.width            = 31;  //• SHOULD BE 32, BUT TO GET AROUND A APPLE QD3D ACCEL CARD DRIVER BUG...
  169.     markerData.bitmap.height        = 32;
  170.     markerData.bitmap.rowBytes        = 4;
  171.     markerData.bitmap.bitOrder        = kQ3EndianBig;
  172.     markerData.markerAttributeSet    = Q3AttributeSet_New();
  173.     assert(markerData.markerAttributeSet != NULL);
  174.     
  175.     color.r = 1.0;
  176.     color.g = 1.0;
  177.     color.b = 0.4;
  178.     
  179.     Q3AttributeSet_Add(markerData.markerAttributeSet, kQ3AttributeTypeDiffuseColor, &color);
  180.     
  181.     gGameCrossHairs = Q3Marker_New(&markerData);
  182.     
  183.     Q3Object_Dispose(markerData.markerAttributeSet);
  184.     markerData.markerAttributeSet = NULL;
  185. }
  186.  
  187.  
  188. /* =============================================================================
  189.  *        Game_Exit (external)
  190.  *
  191.  *    Prepares for exit.
  192.  * ========================================================================== */
  193. void Game_Exit(
  194.     void)
  195. {
  196.     if (gGameFPSMarker != NULL)
  197.     {
  198.         Q3Object_Dispose(gGameFPSMarker);
  199.         gGameFPSMarker = NULL;
  200.     }
  201.     
  202.     if (gGameCrossHairs != NULL)
  203.     {
  204.         Q3Object_Dispose(gGameCrossHairs);
  205.         gGameCrossHairs = NULL;
  206.     }
  207. }
  208.  
  209.  
  210. /* =============================================================================
  211.  *        Game_GetState (external)
  212.  *
  213.  *    Returns the game state.
  214.  * ========================================================================== */
  215. TGameState Game_GetState(
  216.     void)
  217. {
  218.     return gGameState;
  219. }
  220.  
  221.  
  222. /* =============================================================================
  223.  *        Game_SetState (external)
  224.  *
  225.  *    Changes the game state.
  226.  * ========================================================================== */
  227. void Game_SetState(
  228.     TGameState            inGameState)
  229. {
  230.     TGameState            prevGameState;
  231.     TDroneObject        drone;
  232.     int                    droneNum;
  233.     
  234.     if (gGameState != inGameState)
  235.     {
  236.         prevGameState = gGameState;
  237.         gGameState = inGameState;
  238.         
  239.         switch (gGameState)
  240.         {
  241.             case kGameState_Playing:
  242.                 // Begin Playing
  243.                 if (prevGameState == kGameState_Stopped)
  244.                 {
  245.                     gGameSelfDrone = SelfDrone_New();
  246.                     
  247.                     // Create some automatic drones
  248.                     for (droneNum = 0; droneNum < kGameAutoDroneCount; droneNum++)
  249.                     {
  250.                         AutoDrone_New(gGameSelfDrone);
  251.                     }
  252.                 }
  253.                 
  254.                 Display_DrawContents();
  255.                 Input_Activate(true);
  256.             break;
  257.             
  258.             case kGameState_Paused:
  259.                 // From Playing to Paused
  260.                 assert(prevGameState != kGameState_Stopped);
  261.                 
  262.                 Game_Silence();
  263.                 Display_DrawContents();
  264.                 Input_Activate(false);
  265.             break;
  266.             
  267.             case kGameState_Stopped:
  268.                 // From Playing or Paused to Stopped
  269.                 while ((drone = Drone_Next(NULL)) != NULL)
  270.                 {
  271.                     Drone_Dispose(drone);
  272.                 }
  273.                 
  274.                 gGameSelfDrone = NULL;
  275.                 
  276.                 Display_DrawContents();
  277.                 Input_Activate(false);
  278.             break;
  279.         }
  280.     }
  281. }
  282.  
  283.  
  284. /* =============================================================================
  285.  *        Game_KeyDown (external)
  286.  *
  287.  *    Handles a key press.  The fire button happens immediately.  The most
  288.  *    recently pressed of the directional keys is remembered for use in
  289.  *    Game_DirectionalKey.
  290.  * ========================================================================== */
  291. void Game_KeyDown(
  292.     unsigned long    inChar,
  293.     unsigned long    inKeyCap)
  294. {
  295.     switch (gGameState)
  296.     {
  297.         case kGameState_Playing:
  298.             switch (inKeyCap)
  299.             {
  300.                 case kKeyCap_Numeric1:
  301.                 case kKeyCap_Numeric2:
  302.                 case kKeyCap_Numeric3:
  303.                 case kKeyCap_Numeric4:
  304.                 case kKeyCap_Numeric6:
  305.                 case kKeyCap_Numeric7:
  306.                 case kKeyCap_Numeric8:
  307.                 case kKeyCap_Numeric9:
  308.                     gGameDirectionalKeyCap = inKeyCap;
  309.                     gGameDirectionalKeyDown = true;
  310.                 break;
  311.                 
  312.                 case kKeyCap_SpaceBar:
  313.                     Drone_Fire(gGameSelfDrone);
  314.                 break;
  315.                 
  316.                 default:
  317.                     switch (inChar)
  318.                     {
  319.                         case 'h':
  320.                         case 'H':
  321.                             gGameHUDVisible = !gGameHUDVisible;
  322.                         break;
  323.                         
  324.                         case 'f':
  325.                         case 'F':
  326.                             gGameFPSVisible = !gGameFPSVisible;
  327.                         break;
  328.                     }
  329.             }
  330.         break;
  331.         
  332.         case kGameState_Paused:
  333.             //•
  334.         break;
  335.         
  336.         case kGameState_Stopped:
  337.             //•
  338.         break;
  339.     }
  340. }
  341.  
  342.  
  343. /* =============================================================================
  344.  *        Game_Process (external)
  345.  *
  346.  *    Handles idle time by moving the game ahead one time step.  Only called if
  347.  *    the game is in "play" state.
  348.  * ========================================================================== */
  349. void Game_Process(
  350.     void)
  351. {
  352.     UnsignedWide        wide;
  353.     unsigned long        now;
  354.     Str15                str;
  355.     CGrafPtr            savePort;
  356.     GDHandle            saveGDevice;
  357.     TDroneObject        drone;
  358.     TDroneObject        next;
  359.     TQ3Point3D            position;
  360.     TQ3Vector3D            direction;
  361.     TQ3Vector3D            up;
  362.     TQ3Matrix4x4        matrix;
  363.     float                xAxis;
  364.     float                yAxis;
  365.     Boolean                ok;
  366.     UInt32                count;
  367.     
  368.     // Find the frame rate
  369.     Microseconds(&wide);
  370.     now = wide.lo;
  371.     
  372.     if (gGameTime != 0)
  373.     {
  374.         // Find the interval for the last frame
  375.         gGameInterval = 0.000001*(now-gGameTime);
  376.         
  377.         // Limit frame rate to a resonable number
  378.         if (gGameInterval > MAX_INTERVAL)
  379.         {
  380.             gGameInterval = MAX_INTERVAL;
  381.         }
  382.         
  383.         // Find corresponding frames per second
  384.         gGameFramesPerSecond = 1.0/gGameInterval;
  385.     }
  386.     
  387.     gGameTime = now;
  388.     
  389.     // Update the FPS marker
  390.     if (gGameFPSVisible)
  391.     {
  392.         sprintf((char*) str, "x%.1f", gGameFramesPerSecond);
  393.         str[0] = strlen((char*) str) - 1;
  394.         
  395.         GetGWorld(&savePort, &saveGDevice);
  396.         SetGWorld(gGameFPSGWorld, NULL);
  397.         
  398.         EraseRect(&gGameFPSGWorld->portRect);
  399.         
  400.         MoveTo(gGameFPSGWorld->portRect.left+gGameFPSGWorld->portRect.right-StringWidth(str) >> 1, 10);
  401.         DrawString(str);
  402.         
  403.         SetGWorld(savePort, saveGDevice);
  404.         
  405.         Q3Marker_SetBitmap(gGameFPSMarker, &gGameFPSMarkerData.bitmap);
  406.     }
  407.     
  408.     // Grab the key map
  409.     GetKeys(gGameKeyMap);
  410.     
  411.     // Change direction while key is held down
  412.     Game_DirectionalKey();
  413.     Game_CursorKey();
  414.     
  415.     // Get and process state-based inputs
  416.     Input_GetState(&xAxis, &yAxis);
  417.     
  418.     SelfDrone_Turn(
  419.             gGameSelfDrone,
  420.             xAxis*gGameInterval*AXIS_ROTATE_RATE,
  421.             yAxis*gGameInterval*AXIS_ROTATE_RATE);
  422.     
  423.     // Get and process input events
  424.     ok = true;
  425.     do
  426.     {
  427.         switch (Input_GetEvent())
  428.         {
  429.             case kInputEvent_None:
  430.                 // No more input events to process
  431.                 ok = false;
  432.             break;
  433.             
  434.             case kInputEvent_Fire:
  435.                 // Fire button
  436.                 Drone_Fire(gGameSelfDrone);
  437.             break;
  438.             
  439.             case kInputEvent_Pause:
  440.                 // Toggle paused/play state
  441.                 switch (gGameState)
  442.                 {
  443.                     case kGameState_Playing:
  444.                         Game_SetState(kGameState_Paused);
  445.                     break;
  446.                     
  447.                     case kGameState_Paused:
  448.                         Game_SetState(kGameState_Playing);
  449.                     break;
  450.                     
  451.                     case kGameState_Stopped:
  452.                         // do nothing
  453.                     break;
  454.                 }
  455.             break;
  456.             
  457.             case kInputEvent_ShowHUD:
  458.                 // Toggle HMD display
  459.                 gGameHUDVisible = !gGameHUDVisible;
  460.             break;
  461.             
  462.             case kInputEvent_ShowFPS:
  463.                 // Toggle FPS display
  464.                 gGameFPSVisible = !gGameFPSVisible;
  465.             break;
  466.         }
  467.     }
  468.     while (ok);
  469.     
  470.     // Move all the drones, mark any to be deleted
  471.     for (drone = Drone_Next(NULL); drone != NULL; drone = Drone_Next(drone))
  472.     {
  473.         Drone_Move(drone);
  474.     }
  475.     
  476.     // Delete the marked drones
  477.     drone = Drone_Next(NULL);
  478.     while (drone != NULL)
  479.     {
  480.         next = Drone_Next(drone);
  481.         
  482.         if (Drone_GetMark(drone))
  483.         {
  484.             Drone_Dispose(drone);
  485.         }
  486.         
  487.         drone = next;
  488.     }
  489.     
  490.     // Move the viewer to follow the self drone
  491.     Drone_GetPosition(gGameSelfDrone, &position);
  492.     Drone_GetDirection(gGameSelfDrone, &direction);
  493.     Drone_GetUp(gGameSelfDrone, &up);
  494.     
  495.     Display_SetViewerPosition(&position, &direction, &up);
  496.     
  497.     // Move the listener to follow the self drone
  498.     Drone_GetMatrix(gGameSelfDrone, &matrix);
  499.     SSpListener_SetTransform(Sound_GetListener(), &matrix);
  500.     
  501.     // Change the localized sounds
  502.     for (drone = Drone_Next(NULL); drone != NULL; drone = Drone_Next(drone))
  503.     {
  504.         Drone_UpdateSound(drone);
  505.     }
  506.     
  507.     // Time to retire?
  508.     
  509.     // NOTE: This is not the best way to determine if the game is done.  We
  510.     // should probably ask each drone if it thinks the game should continue.
  511.     // Only AutoDrones would respond yes.  Then we'd "or" the results.
  512.     
  513.     count = 0;
  514.     for (drone = Drone_Next(NULL); drone != NULL; drone = Drone_Next(drone))
  515.     {
  516.         count += 1;
  517.     }
  518.     
  519.     if (count == 1)
  520.     {
  521.         // Only the autodrone is left -- time to quit
  522.         Game_SetState(kGameState_Stopped);
  523.     }
  524. }
  525.  
  526.  
  527. /* =============================================================================
  528.  *        Game_Submit (external)
  529.  *
  530.  *    Submits all the 3D geometry of the game.
  531.  * ========================================================================== */
  532. void Game_Submit(
  533.     TQ3ViewObject        inView)
  534. {
  535.     TDroneObject        drone;
  536.     TQ3Point3D            position;
  537.     TQ3Vector3D            direction;
  538.     TQ3Vector3D            up;
  539.     TQ3Vector3D            v;
  540.     TQ3Point3D            markerPosition;
  541.     
  542.     assert(inView != NULL);
  543.     
  544.     // Submit the drones
  545.     for (drone = Drone_Next(NULL); drone != NULL; drone = Drone_Next(drone))
  546.     {
  547.         Drone_Submit(drone, gGameHUDVisible, inView);
  548.     }
  549.     
  550.     // Get information about the camera position
  551.     Drone_GetPosition(gGameSelfDrone, &position);
  552.     Drone_GetDirection(gGameSelfDrone, &direction);
  553.     Drone_GetUp(gGameSelfDrone, &up);
  554.     
  555.     // Submit the spacejunk
  556.     Space_Submit(inView, &position, &direction);
  557.     
  558.     // Submit the FPS marker if the caps lock key is down
  559.     if (gGameFPSVisible)
  560.     {
  561.         Q3Point3D_Vector3D_Add(&position, &direction, &markerPosition);
  562.         Q3Vector3D_Scale(&up, -0.6, &v);
  563.         Q3Point3D_Vector3D_Add(&markerPosition, &v, &markerPosition);
  564.         Q3Marker_SetPosition(gGameFPSMarker, &markerPosition);
  565.         Q3Object_Submit(gGameFPSMarker, inView);
  566.     }
  567.     
  568.     // Submit the crosshairs
  569.     if (gGameHUDVisible)
  570.     {
  571.         Q3Point3D_Vector3D_Add(&position, &direction, &markerPosition);
  572.         Q3Marker_SetPosition(gGameCrossHairs, &markerPosition);
  573.         Q3Object_Submit(gGameCrossHairs, inView);
  574.     }
  575. }
  576.  
  577.  
  578. /* =============================================================================
  579.  *        Game_DirectionalKey (internal)
  580.  *
  581.  *    Takes action based on the currently pressed directional key.  If the most
  582.  *    recently pressed key is still down, or if this is the first time for the
  583.  *    key, then the main drone is turned.
  584.  * ========================================================================== */
  585. void Game_DirectionalKey(
  586.     void)
  587. {
  588.     Boolean                keyIsDown;
  589.     unsigned long        index;
  590.     unsigned long        mask;
  591.     float                horz;
  592.     float                vert;
  593.     
  594.     // Do we even have a key to check?
  595.     if (gGameDirectionalKeyCap != 0)
  596.     {
  597.         // Check the state of the directional key that went down last
  598.         keyIsDown = false;
  599.         
  600.         if (gGameDirectionalKeyDown)
  601.         {
  602.             // Key was pressed on this turn
  603.             keyIsDown = true;
  604.             gGameDirectionalKeyDown = false;
  605.         }
  606.         else
  607.         {
  608.             // KeyMap is scrambled because of funky old Pascal bit packing rules.
  609.             // The keycap may be decomposed as follows:
  610.             //
  611.             //        +---+---+---+---|---+---+---+---+
  612.             //        | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
  613.             //        +---+---+---+---|---+---+---+---+
  614.             //        | 0 | index | ~byte |    bit    |
  615.             //        +---+---+---+---|---+---+---+---+
  616.             
  617.             index = gGameDirectionalKeyCap >> 5 & 0x03;
  618.             mask = 1 << ((gGameDirectionalKeyCap & 0x1F) ^ 0x18);
  619.             
  620.             if (gGameKeyMap[index] & mask)
  621.             {
  622.                 // Key is still down
  623.                 keyIsDown = true;
  624.             }
  625.             else
  626.             {
  627.                 // The key has been released
  628.                 gGameDirectionalKeyCap = 0;
  629.                 
  630.                 //• TODO: Search for any other directional key down
  631.             }
  632.         }
  633.         
  634.         // Do the action while the directional key is still down
  635.         if (keyIsDown)
  636.         {
  637.             // Find the amount of turn
  638.             horz = 0.0;
  639.             vert = 0.0;
  640.             
  641.             switch (gGameDirectionalKeyCap)
  642.             {
  643.                 case kKeyCap_Numeric1:
  644.                     horz = -INV_SQRT_TWO*KEY_ROTATE_RATE;
  645.                     vert = horz;
  646.                 break;
  647.                 
  648.                 case kKeyCap_Numeric2:
  649.                     vert = -KEY_ROTATE_RATE;
  650.                 break;
  651.                 
  652.                 case kKeyCap_Numeric3:
  653.                     horz = INV_SQRT_TWO*KEY_ROTATE_RATE;
  654.                     vert = -horz;
  655.                 break;
  656.                 
  657.                 case kKeyCap_Numeric4:
  658.                     horz = -KEY_ROTATE_RATE;
  659.                 break;
  660.                 
  661.                 case kKeyCap_Numeric6:
  662.                     horz = KEY_ROTATE_RATE;
  663.                 break;
  664.                 
  665.                 case kKeyCap_Numeric7:
  666.                     vert = INV_SQRT_TWO*KEY_ROTATE_RATE;
  667.                     horz = -vert;
  668.                 break;
  669.                 
  670.                 case kKeyCap_Numeric8:
  671.                     vert = KEY_ROTATE_RATE;
  672.                 break;
  673.                 
  674.                 case kKeyCap_Numeric9:
  675.                     horz = INV_SQRT_TWO*KEY_ROTATE_RATE;
  676.                     vert = horz;
  677.                 break;
  678.             }
  679.             
  680.             // Execute the turn
  681.             SelfDrone_Turn(gGameSelfDrone, horz*gGameInterval, vert*gGameInterval);
  682.         }
  683.     }
  684. }
  685.  
  686.  
  687. /* =============================================================================
  688.  *        Game_CursorKey (internal)
  689.  *
  690.  *    Takes action based on the currently pressed cursor key.
  691.  * ========================================================================== */
  692. void Game_CursorKey(
  693.     void)
  694. {
  695.     float                horz;
  696.     float                vert;
  697.     
  698.     horz = 0.0;
  699.     vert = 0.0;
  700.     
  701.     // Grab the "up" cursor arrow
  702.     if (gGameKeyMap[3] & 0x00000040)
  703.     {
  704.         vert += KEY_ROTATE_RATE;
  705.     }
  706.     
  707.     // Grab the "down" cursor arrow
  708.     if (gGameKeyMap[3] & 0x00000020)
  709.     {
  710.         vert -= KEY_ROTATE_RATE;
  711.     }
  712.     
  713.     // Grab the "right" cursor arrow
  714.     if (gGameKeyMap[3] & 0x00000010)
  715.     {
  716.         horz += KEY_ROTATE_RATE;
  717.     }
  718.     
  719.     // Grab the "left" cursor arrow
  720.     if (gGameKeyMap[3] & 0x00000008)
  721.     {
  722.         horz -= KEY_ROTATE_RATE;
  723.     }
  724.     
  725.     // Execute the turn
  726.     if (horz != 0.0 || vert != 0.0)
  727.     {
  728.         SelfDrone_Turn(gGameSelfDrone, horz*gGameInterval, vert*gGameInterval);
  729.     }
  730. }
  731.  
  732.  
  733. /* =============================================================================
  734.  *        Game_Silence (external)
  735.  *
  736.  *    Stops all sounds.
  737.  * ========================================================================== */
  738. void Game_Silence(
  739.     void)
  740. {
  741.     TDroneObject        drone;
  742.     
  743.     for (drone = Drone_Next(NULL); drone != NULL; drone = Drone_Next(drone))
  744.     {
  745.         Drone_Silence(drone);
  746.     }
  747. }
  748.  
  749.  
  750.